﻿/******************************************************************** 
 * Cerebrum Embedded System Design Automation Framework
 * Copyright (C) 2010  The Pennsylvania State University
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 ********************************************************************/
/* //////////////////////////////////////////////
// File Name : XpsBuilder.cs
// Created By: Abdulrahman Abumurad
// Date : 5/25/2010
// Description : 
 * >> (29 May 2010) Matthew Cotter: Disabled (by default) inference and insertion of Chipscope ILAs in designs.
 * >> (26 May 2010) Matthew Cotter: Added support for automatic inference and insertion of Chipscope ILAs.
// >> ( 9 May 2010) Matthew Cotter: Added support for Platform-specified top-level ports to facilitate connections between required components.
// >> (15 Feb 2011) Matthew Cotter: Overhaul as part of code reorganization to facilitate uniform access to/from Component/Core objects.
//                                      Methods to locate component and core directories were removed to the global objects to facilitate uniform access.
//                                      Restructured code to support accesses to new component and core objects.
// >> (27 Jan 2011) Matthew Cotter: Removed address validation from tool flow.  Retrieval of remote MPD files is still required by UCF generation, however.
// >> ( 7 Jan 2011) Matthew Cotter: Corrected (and fully implemented) support of remote core search for sub-cores defined by not located locally.
// >> (16 Dec 2010) Matthew Cotter: Added support of core-based valid conditions associated with ports attached to FPGA interfaces.  This is in support of allowing a signal 
//                                      FPGA pin to be tied to different core signals based on the cores parameters. (i.e. LVDS Lanes that may be used for either RX or TX 
//                                      depending on core configuration)
// >> (19 Aug 2010) Matthew Cotter: Updated LocateCoreDirectory() to use a single ordered list of paths rather than multiple explicit paths. 
// >> (16 Aug 2010) Matthew Cotter: Corrected bug in error/output that caused an error to be generated that falsely 
//                                     indicated an error occured in validating core addresses.
// >> ( 7 Jul 2010) Matthew Cotter: Updated Status messages in output.
/////////////////////////////////////////////// */


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Xml;
using System.IO;
using ICSharpCode.SharpZipLib.Tar;
using FalconGlobal;
using FalconPathManager;
using FalconClockManager;
using CerebrumSharedClasses;
using System.Collections;
using CerebrumNetronObjects;
using CerebrumSharedClasses.Platform_Details;
using CerebrumSharedClasses.MPD_Interfaces;

namespace FalconXpsBuilder
{
    /// <summary>
    /// Defines the properties and methods required to contruct an XPS project and integrate a set of assigned IP cores into its design.
    /// </summary>
    /// <seealso href="https://www.cse.psu.edu/svn/mdl/falcon_repository/trunk/Software/Cerebrum/Documentation/XpsBuilder Specification.pdf">
    /// XPS Builder Documentation</seealso>
    public class XpsBuilder : IFalconLibrary
    {
        #region Message Event Manager

        /// <summary>
        /// Event fired when a message has been generated by the library
        /// </summary>
        public event MessageEventDelegate MessageEvent;
        /// <summary>
        /// Raises an event indicating that a message has been generated.
        /// </summary>
        /// <param name="Message">The message to be transmitted</param>
        /// <param name="Args">List of replacements for token placeholders in the message.</param>
        public void RaiseMessageEvent(string Message, params object[] Args)
        {
            string outputText = Message;
            for (int i = 0; i < Args.Length; i++)
            {
                if (Args[i] != null)
                {
                    outputText = outputText.Replace("{" + i.ToString() + "}", Args[i].ToString());
                }
                else
                {
                    outputText = outputText.Replace("{" + i.ToString() + "}", string.Empty);
                }
            }
            if (MessageEvent != null)
            {
                MessageEvent(outputText);
            }
            else
            {
                Console.WriteLine(outputText);
            }
        }

        #endregion
        
        /// <summary>
        /// Default constructor.
        /// </summary>
        public XpsBuilder()
        {
            this.AutoInferChipscopes = false;
        }

        #region Properties and Members

        /// <summary>
        /// Static "constant" used to indicate the version parameter written to MHS files when they are generated
        /// </summary>
        public static string MHS_VERSION = "2.1.0";

        /// <summary>
        /// The FileServices class that is used by the XpsBuilder to transfer files to and from the remote synthesis server.
        /// </summary>
        public FileServices FileService = new FileServices();

        /// <summary>
        /// The XpsProjectOptions that define several key configuration parameters that are specific to the XPS project being built.
        /// </summary>
        public XpsProjectOptions ProjectOpts = new XpsProjectOptions();

        /// <summary>
        /// Generic class that supports reconfiguration of cores within the project MHS file based on custom configuration specified by the user design.
        /// </summary>
        public MHSConfig ConfigMHS = new MHSConfig();

        /// <summary>
        /// FalconPathManager object used to manage the project paths.
        /// </summary>
        public PathManager PathMan;


        /// <summary>
        /// Determines whether the XPS Project Builder will automatically infer Chipscope signals and ILAs on each Pcore in the design.
        /// </summary>
        public bool AutoInferChipscopes { get; set; }
        #endregion
        
        #region UCF Generation and Processing
        /// <summary>
        /// Generates the User-Constraint File for the current XPS Project.
        /// </summary>
        public void GenerateUCF(FPGA fpga, List<ComponentCore> Cores, List<string> Ports)
        {
            try
            {
                List<string> UnMatchedPorts = new List<string>();
                List<string> ExternalPortMaps = new List<string>();
                List<string> UCFConstraints = new List<string>();

                // First process cores that specify the interface instance required/desired
                foreach (ComponentCore CompCore in ProjectOpts.PCoresList)
                {
                    if (CompCore.MappedFPGA == fpga.Instance)
                    {
                        CerebrumCore CC = CompCore.OwnerComponent;
                        if (CC == null)
                        {
                            // Infrastructure core, not part of a higher-level "Component"
                            FileInfo localMPD = CompCore.RetrieveMPD(PathMan, FileService);
                            if (localMPD != null)
                            {
                                CompCore.ParseMPD(localMPD.FullName);
                            }
                            continue;
                        }
                        CompCore.InterfaceInstances = (string)CompCore.Properties.GetValue(CerebrumPropertyTypes.CEREBRUMPROPERTY, "HardwareInterfaces");
                        Debug.WriteLine(String.Format("PCore {0} is assigned the following hardware interfaces: {1}", CompCore.CoreInstance, CompCore.InterfaceInstances));
                        if ((CompCore.InterfaceInstances != null) && (CompCore.InterfaceInstances != string.Empty))
                        {
                            UCFConstraints = ProcessCoreInterfaces(fpga, UnMatchedPorts, ExternalPortMaps, UCFConstraints, CompCore);
                        }
                    } // Verified core maps to current fpga
                } // Finished searching pcore list

                // Finally, process cores that may require an interface, but don't specify an instance
                foreach (ComponentCore CompCore in ProjectOpts.PCoresList)
                {
                    if (CompCore.MappedFPGA == fpga.Instance)
                    {
                        CerebrumCore CC = CompCore.OwnerComponent;
                        if (CC == null)
                        {
                            // Infrastructure core, not part of a higher-level "Component"
                            FileInfo localMPD = CompCore.RetrieveMPD(PathMan, FileService);
                            if (localMPD != null)
                            {
                                CompCore.ParseMPD(localMPD.FullName);
                            }
                            continue;
                        }
                        if ((CompCore.InterfaceInstances == null) && (CompCore.InterfaceInstances == string.Empty))
                        {
                            UCFConstraints = ProcessCoreInterfaces(fpga, UnMatchedPorts, ExternalPortMaps, UCFConstraints, CompCore);
                        }
                    } // Verified core maps to current fpga
                } // Finished searching pcore list
                // Clock and Reset pin constraints


                #region Debug Output Unbound Ports
                Debug.WriteLine("********************************************");
                for (int i = 0; i < UnMatchedPorts.Count; i++)
                {
                    Debug.WriteLine(UnMatchedPorts[i]);
                }
                Debug.WriteLine("********************************************");
                #endregion
            
                #region Locate clock interface
                foreach (FPGA_IO_Interface iface in fpga.Interfaces)
                {
                    if (String.Compare(iface.IOType, "Xil_Clock_V1", true) == 0)
                    {
                        string ClkPin = string.Empty;
                        string ClkFreq = string.Empty;
                        foreach (Internal_IO_Parameter param in iface.Parameters)
                        {
                            if (String.Compare(param.ParameterName, "CLK_FREQ", true) == 0)
                            {
                                ClkFreq = param.ParameterValue;
                            }
                        }
                        foreach (Internal_IO_Port port in iface.Ports)
                        {
                            if (String.Compare(port.PortName, "USER_SYS_CLK", true) == 0)
                            {
                                ClkPin = port.SignalName;
                            }
                        }
                        foreach (FPGA_IO_Port fpgaPort in fpga.Ports)
                        {
                            if (String.Compare(fpgaPort.PortName, ClkPin, true) == 0)
                            {
                                ExternalPortMaps.Add(String.Format("PORT clock_generator_sys_clk_pin = dcm_clk_s, DIR = I, SIGIS = CLK, CLK_FREQ = {0}", ClkFreq));
                                UCFConstraints.Add(String.Format("Net clock_generator_sys_clk_pin TNM_NET = sys_clk_pin"));
                                UCFConstraints.Add(String.Format("TIMESPEC TS_sys_clk_pin = PERIOD sys_clk_pin {0}", ClkFreq));
                                UCFConstraints.Add(String.Format("Net clock_generator_sys_clk_pin {0}", fpgaPort.UCF_Net_String));
                            }
                        }
                    }
                }
                #endregion

                #region Locate Reset interface
                foreach (FPGA_IO_Interface iface in fpga.Interfaces)
                {
                    if (String.Compare(iface.IOType, "Xil_Reset_V1", true) == 0)
                    {
                        string RstPin = string.Empty;
                        string RstPol = string.Empty;
                        foreach (Internal_IO_Parameter param in iface.Parameters)
                        {
                            if (String.Compare(param.ParameterName, "RST_POLARITY", true) == 0)
                            {
                                RstPol = param.ParameterValue;
                            }
                        }
                        foreach (Internal_IO_Port port in iface.Ports)
                        {
                            if (String.Compare(port.PortName, "FPGARESET", true) == 0)
                            {
                                RstPin = port.SignalName;
                            }
                        }
                        foreach (FPGA_IO_Port fpgaPort in fpga.Ports)
                        {
                            if (String.Compare(fpgaPort.PortName, RstPin, true) == 0)
                            {
                                ExternalPortMaps.Add(String.Format("PORT sys_rst_pin = sys_rst_s, DIR = I, SIGIS = RST, RST_POLARITY = {0}", RstPol));
                                UCFConstraints.Add(String.Format("Net sys_rst_pin TIG"));
                                UCFConstraints.Add(String.Format("Net sys_rst_pin {0}", fpgaPort.UCF_Net_String));
                            }
                        }
                    }
                }
                #endregion

                #region Write UCF and Rewrite MHS
                string UCFLocation = String.Format("{0}\\{1}\\system.ucf", ProjectOpts.XpsProjectDirectory, "data");
                StreamWriter ucfWriter = new StreamWriter(UCFLocation);
                foreach (string UCFLine in UCFConstraints)
                {
                    string LineToWrite = UCFLine;
                    string prefix = string.Empty;
                    string suffix = ";";
                    while (LineToWrite.EndsWith(";"))
                        LineToWrite = LineToWrite.Substring(0, LineToWrite.Length - 1);
                    if (LineToWrite.StartsWith("#"))
                    {
                        prefix = "\n";
                        suffix = string.Empty;
                    }
                    ucfWriter.Write(String.Format("{0}{1}{2}\n", prefix, LineToWrite, suffix));
                }
                ucfWriter.Close();

                ExternalPortMaps.AddRange(Ports);
                foreach (FPGA_External_Port EP in fpga.ExternalPorts)
                {
                    string NewPort = String.Format("PORT {0} = {0}", EP.Name);
                    string[] PortAttributes = EP.Attributes.Keys.ToArray();
                    for (int i = 0; i < PortAttributes.Length; i++)
                    {
                        NewPort = String.Format("{0}, {1} = {2}", NewPort, PortAttributes[i], EP.Attributes[PortAttributes[i]]);
                    }
                    ExternalPortMaps.Add(NewPort);
                }
                string MHSFile = String.Format("{0}\\system.mhs", ProjectOpts.XpsProjectDirectory);
                RewriteMHS(MHSFile, Cores, ExternalPortMaps);
                #endregion
            }
            catch (Exception ex)
            {
                ErrorReporting.TraceException(ex, true);
            }
        }

        private List<string> ProcessCoreInterfaces(FPGA fpga, List<string> UnMatchedPorts, List<string> ExternalPortMaps, List<string> UCFConstraints, ComponentCore CompCore)
        {
            FileInfo localMPD = CompCore.RetrieveMPD(PathMan, FileService);
            if (localMPD != null)
            {
                CompCore.ParseMPD(localMPD.FullName);
            }

            List<string> UsedInterfaces = new List<string>();
            if ((CompCore.InterfaceInstances != null) && (CompCore.InterfaceInstances != string.Empty))
            {
                string HWInterfaces = (string)CompCore.Properties.GetValue(CerebrumPropertyTypes.CEREBRUMPROPERTY, "HardwareInterfaces");
                UsedInterfaces.AddRange(HWInterfaces.Split(new char[] {';'}, StringSplitOptions.RemoveEmptyEntries));
            }
            StringBuilder UsedIFDebug = new StringBuilder();
            UsedIFDebug.AppendFormat("[{0}] Component Core: {1}\n", fpga.Instance, CompCore.CoreInstance);
            foreach (KeyValuePair<string, PCoreIOInterface> ifPair in CompCore.Interfaces)
            {
                PCoreIOInterface pcoreIF = ifPair.Value;
                UsedIFDebug.AppendFormat("\t\tInterface: {0} of type {1}\n", pcoreIF.IO_IF, pcoreIF.IO_TYPE);
            }
            Trace.WriteLine(UsedIFDebug.ToString());
            
            #region Match interfaces
            foreach (KeyValuePair<string, PCoreIOInterface> ifPair in CompCore.Interfaces)
            {
                #region Search FPGA interfaces for one matching PCore interface
                PCoreIOInterface pcoreIF = ifPair.Value;
                Trace.WriteLine(String.Format("Determining if PCore Interface ({0} of type {1}) is required...", pcoreIF.IO_IF, pcoreIF.IO_TYPE));
                foreach (FPGA_IO_Interface fpgaIF in fpga.Interfaces)
                {
                    //Trace.WriteLine(String.Format("\tExamining FPGA Interface: {0} of type {1}", fpgaIF.Instance, fpgaIF.IOType));
                    // Split on ; 
                    // Add to list
                    // List.Contains or List.Count == 0
                    if ((fpgaIF.Available) &&
                        (String.Compare(fpgaIF.IOType, pcoreIF.IO_TYPE, true) == 0) &&
                        ((UsedInterfaces.Contains(fpgaIF.Instance)) || (UsedInterfaces.Count == 0))
                       )
                    {
                        Trace.WriteLine(String.Format("\tFound match on {0}!", fpgaIF.Instance));

                        #region Process PCore interface ports
                        foreach (PCorePort pcorePort in pcoreIF.Ports)
                        {
                            // Test that port is valid based on parameters
                            if (Conditions.EvaluateAsBoolean(CompCore.TranslateString(pcorePort.ValidCond)))
                            {
                                // Start Piecing it together
                                if (fpgaIF.Available)
                                {
                                    UCFConstraints.Add(String.Format("########################################################################"));
                                    UCFConstraints.Add(String.Format("# FPGA Interface constraints for PCore: {0}, Interface Instance: {1}", CompCore.CoreInstance, fpgaIF.Instance));
                                    UCFConstraints.Add(String.Format("########################################################################\n"));

                                    fpgaIF.Available = false;
                                }
                                                
                                #region Generate external / internal pin names and connection
                                // Create the MHS port definition
                                pcorePort.ParseVector(CompCore.TranslateString(pcorePort.VectorString));
                                string ExternalPortName = String.Format("{0}_{1}_pin", CompCore.CoreInstance, pcorePort.PortName);
                                string ExtraPortInfo = String.Format(
                                    "{0}, {1}, {2}, {3}",
                                    (pcorePort.Direction != string.Empty ? String.Format("DIR = {0}", pcorePort.Direction) : string.Empty),
                                    (pcorePort.IsVector ? String.Format("VEC = [{0}:{1}]", pcorePort.VectorHigh, pcorePort.VectorLow) : string.Empty),
                                    (pcorePort.SigIs != string.Empty ? String.Format("SIGIS = {0}", pcorePort.SigIs) : string.Empty),
                                    (pcorePort.Sensitivity != string.Empty ? String.Format("SENSITIVITY = {0}", pcorePort.Sensitivity) : string.Empty)
                                    ).Trim();
                                while (ExtraPortInfo.Contains(", ,"))
                                    ExtraPortInfo = ExtraPortInfo.Replace(", ,", ",").Trim();
                                while (ExtraPortInfo.EndsWith(","))
                                    ExtraPortInfo = ExtraPortInfo.Trim(',').Trim();

                                string ExternalPortDef = String.Format("PORT {0} = {0}, {1}", ExternalPortName, ExtraPortInfo).Trim();

                                // Tie the External port to the Core
                                string CorePortDef = String.Format("PORT {0} = {1}",
                                    pcorePort.PortName,
                                    ExternalPortName
                                    );

                                #endregion

                                #region Process all pins in a vector
                                bool bFoundSignalMatch = false;
                                int VectorIndex = pcorePort.VectorLow;
                                while (VectorIndex <= pcorePort.VectorHigh)
                                {
                                    string TargetPortMatch = string.Empty;
                                    string SignalPortMatch = pcorePort.IO_IS;
                                    string VectorPortMatch = String.Format("{0}[{1}]", pcorePort.IO_IS, VectorIndex.ToString());
                                    string UnitVectorPortMatch = String.Format("{0}[0]", pcorePort.IO_IS);
                                    

                                    #region Search FPGA Interface Ports for one that matches IO_IS
                                    //Trace.WriteLine(String.Format("Searching for FPGA signal matching {0}", TargetPortMatch));
                                    foreach (Internal_IO_Port fpgaIFPort in fpgaIF.Ports)
                                    {
                                        if ((pcorePort.IsVector && (String.Compare(VectorPortMatch, fpgaIFPort.IO_IS, true) == 0)) ||
                                            (!pcorePort.IsVector && (String.Compare(SignalPortMatch, fpgaIFPort.IO_IS, true) == 0)) ||
                                            (!pcorePort.IsVector && (String.Compare(UnitVectorPortMatch, fpgaIFPort.IO_IS, true) == 0)))
                                        {
                                            string Condition = CompCore.TranslateString(fpgaIFPort.ValidCondition);
                                            if (Conditions.EvaluateAsBoolean(Condition))
                                            {
                                                if ((pcorePort.IsVector && (String.Compare(VectorPortMatch, fpgaIFPort.IO_IS, true) == 0)))
                                                    TargetPortMatch = VectorPortMatch;
                                                if ((!pcorePort.IsVector && (String.Compare(SignalPortMatch, fpgaIFPort.IO_IS, true) == 0)) ||
                                                    (!pcorePort.IsVector && (String.Compare(UnitVectorPortMatch, fpgaIFPort.IO_IS, true) == 0)))
                                                {
                                                    TargetPortMatch = SignalPortMatch;
                                                }
                                                //Trace.WriteLine(String.Format("Found signal {0}", fpgaIFPort.SignalName));
                                                #region Search FPGA Ports for Signal that Matches Interface Port
                                                string ExternalFPGASignal = fpgaIFPort.SignalName;
                                                bool bFoundMatch = false;
                                                foreach (FPGA_IO_Port fpgaPin in fpga.Ports)
                                                {
                                                    if (String.Compare(ExternalFPGASignal, fpgaPin.SignalName, true) == 0)
                                                    {
                                                        bool bUsePin = true;
                                                        bUsePin = Conditions.EvaluateAsBoolean(CompCore.TranslateString(fpgaPin.ValidCond));
                                                        bUsePin = bUsePin || Conditions.EvaluateAsBoolean(CompCore.OwnerComponent.TranslateString(fpgaPin.ValidCond));
                                                        if (bUsePin)
                                                        {
                                                            //Trace.WriteLine(String.Format("Found pin {0}", fpgaPin.SignalName));
                                                            // Tie it to the UCF Net
                                                            string UCF_String = String.Format("Net {0}{1} {2}",
                                                                ExternalPortName,
                                                                (pcorePort.IsVector ? String.Format("<{0}>", VectorIndex.ToString()) : string.Empty),
                                                                fpgaPin.UCF_Net_String
                                                                );
                                                            UCFConstraints.Add(UCF_String);
                                                        }
                                                        bFoundMatch = true;
                                                        bFoundSignalMatch = true;
                                                        break;
                                                    }
                                                }
                                                if (!bFoundMatch)
                                                {
                                                    UnMatchedPorts.Add(String.Format("{0} {1}", CompCore.CoreInstance, TargetPortMatch));
                                                }
                                                #endregion
                                            }
                                        }
                                        else if (!pcorePort.IsVector)
                                        {
                                        }
                                    }
                                    #endregion

                                    VectorIndex++;
                                }
                                if (bFoundSignalMatch)
                                {
                                    CompCore.Properties.SetValue(CerebrumPropertyTypes.PORT, pcorePort.PortName, ExternalPortName, true);
                                    ExternalPortMaps.Add(ExternalPortDef);
                                    //Trace.WriteLine(String.Format("Tying port {0} to signal {1}", pcorePort.PortName, ExternalPortName));
                                }
                                #endregion
                            }
                        }
                        #endregion

                        //#region Match FPGA Interface Parameters
                        //foreach (PCoreInterfaceParameter pciop in pcoreIF.Parameters)
                        //{
                        //    foreach (Internal_IO_Parameter iop in fpgaIF.Parameters)
                        //    {
                        //        if (String.Compare(pciop.IO_IS, iop.IO_IS, true) == 0)
                        //        {
                        //            string pName = pciop.ParameterName;
                        //            string pVal = iop.ParameterValue;
                        //            bool bFound = false;
                        //            foreach (CoreParameter cp in Core.Parameters)
                        //            {
                        //                if (string.Compare(cp.Name, pName, true) == 0)
                        //                {
                        //                    bFound = true;
                        //                    cp.Value = pVal;
                        //                    break;
                        //                }
                        //            }
                        //            if (!bFound)
                        //            {
                        //                Core.Parameters.Add(new CoreParameter(pName, pVal));
                        //            }
                        //        }
                        //    }
                        //}
                        //#endregion
                        break;
                    }
                }
                #endregion
            }
            #endregion

            #region Match Adapters
            foreach (FPGA_IO_Adapter adapter in fpga.Adapters)
            {
                if (adapter.CoreName == CompCore.CoreType)
                {
                    foreach (Internal_IO_Port fpgaAdapterPort in adapter.Ports)
                    {
                        string portPin = fpgaAdapterPort.SignalName;
                        foreach (PCorePort pcorePort in CompCore.Interfaces["NONE"].Ports)
                        {
                            if (pcorePort.PortName == fpgaAdapterPort.PortName)
                            {
                                foreach (FPGA_IO_Port fpgaPort in fpga.Ports)
                                {
                                    if (String.Compare(fpgaPort.PortName, portPin, true) == 0)
                                    {
                                        pcorePort.ParseVector(CompCore.TranslateString(pcorePort.VectorString));
                                        string ExternalPortName = String.Format("{0}_{1}_pin", CompCore.CoreInstance, pcorePort.PortName);
                                        string ExtraPortInfo = String.Format(
                                            "{0}, {1}, {2}, {3}",
                                            (pcorePort.Direction != string.Empty ? String.Format("DIR = {0}", pcorePort.Direction) : string.Empty),
                                            (pcorePort.IsVector ? String.Format("VEC = [{0}:{1}]", pcorePort.VectorHigh, pcorePort.VectorLow) : string.Empty),
                                            (pcorePort.SigIs != string.Empty ? String.Format("SIGIS = {0}", pcorePort.SigIs) : string.Empty),
                                            (pcorePort.Sensitivity != string.Empty ? String.Format("SENSITIVITY = {0}", pcorePort.Sensitivity) : string.Empty)
                                            ).Trim();
                                        while (ExtraPortInfo.Contains(", ,"))
                                            ExtraPortInfo = ExtraPortInfo.Replace(", ,", ",").Trim();
                                        while (ExtraPortInfo.EndsWith(","))
                                            ExtraPortInfo = ExtraPortInfo.Trim(',').Trim();

                                        string ExternalPortDef = String.Format("PORT {0} = {0}, {1}", ExternalPortName, ExtraPortInfo).Trim();

                                        string CorePortDef = String.Format("PORT {0} = {1}",
                                            pcorePort.PortName,
                                            ExternalPortName
                                            );

                                        ExternalPortMaps.Add(ExternalPortDef);
                                        CompCore.Properties.SetValue(CerebrumPropertyTypes.PORT, pcorePort.PortName, ExternalPortName, true);
                                        UCFConstraints.Add(String.Format("Net {0} {1}", ExternalPortName, fpgaPort.UCF_Net_String));
                                    }
                                }
                            }
                        }
                    }
                }
            }
            #endregion

            #region Process Custom PCore UCF
            if (CompCore.OwnerComponent != null)
            {
                FileInfo ComponentDef = CoreLibrary.LocateCoreDefinition(PathMan, CompCore.OwnerComponent.CoreLocation);
                FileInfo PCoreUCF = new FileInfo(String.Format("{0}\\{1}", ComponentDef.Directory.FullName, CompCore.CoreUCF));
                if (PCoreUCF.Exists)
                {
                    UCFConstraints.Add(String.Format("########################################################################"));
                    UCFConstraints.Add(String.Format("# Custom constraints for PCore: {0}, Source: {1}", CompCore.CoreInstance, PCoreUCF.Name));
                    UCFConstraints.Add(String.Format("########################################################################\n"));
                    ProcessCustomUCF(PCoreUCF.FullName, fpga, CompCore, ref UCFConstraints);
                }
            }
            #endregion

            return UCFConstraints;
        }

        private void ProcessCustomUCF(string UCFPath, FPGA fpga, ComponentCore CompCore, ref List<string> UCFConstraints)
        {
            try
            {
                XmlDocument xDoc = new XmlDocument();
                xDoc.Load(UCFPath);
                foreach (XmlNode xRoot in xDoc.ChildNodes)
                {
                    if (String.Compare(xRoot.Name, "xml", true) != 0)
                    {
                        foreach (XmlNode xConstraint in xRoot.ChildNodes)
                        {
                            if (xConstraint.NodeType == XmlNodeType.Comment)
                                continue;
                            string ConstraintLine = string.Empty;
                            string ConstraintType = xConstraint.Name;
                            //if ((String.Compare(ConstraintType, "INTERNAL_NET", true) == 0) ||
                            //    (String.Compare(ConstraintType, "EXTERNAL_NET", true) == 0))
                            //{
                            //    ConstraintType = "NET";
                            //}

                            bool bIncludeConstraint = true;
                            foreach (XmlAttribute xAttr in xConstraint.Attributes)
                            {
                                if (String.Compare(xAttr.Name, "Arch", true) == 0)
                                {
                                    // Contraint is architecture dependent
                                    if (String.Compare(fpga.Architecture, xAttr.Value, true) != 0)
                                    {
                                        bIncludeConstraint = false;
                                        break;
                                    }
                                }
                                else if (String.Compare(xAttr.Name, "Device", true) == 0)
                                {
                                    // Contraint is architecture dependent
                                    if (String.Compare(fpga.Device, xAttr.Value, true) != 0)
                                    {
                                        bIncludeConstraint = false;
                                        break;
                                    }
                                }
                                else if (String.Compare(xAttr.Name, "Package", true) == 0)
                                {
                                    // Contraint is architecture dependent
                                    if (String.Compare(fpga.Package, xAttr.Value, true) != 0)
                                    {
                                        bIncludeConstraint = false;
                                        break;
                                    }
                                }
                                else if (String.Compare(xAttr.Name, "Interface", true) == 0)
                                {
                                    // Contraint is architecture dependent
                                    if (String.Compare(CompCore.TargetFamily, xAttr.Value, true) != 0)
                                    {
                                        bIncludeConstraint = false;
                                        break;
                                    }
                                }
                                else if (String.Compare(xAttr.Name, "Contents", true) == 0)
                                {
                                    // Direct contents copy
                                    ConstraintLine = String.Format("{0} {1}", ConstraintType, xAttr.Value);
                                }
                                else if (String.Compare(xAttr.Name, "Valid", true) == 0)
                                {
                                    // Test for validity
                                    bIncludeConstraint = bIncludeConstraint && Conditions.EvaluateAsBoolean(CompCore.TranslateString(xAttr.Value));
                                    bIncludeConstraint = bIncludeConstraint || Conditions.EvaluateAsBoolean(CompCore.OwnerComponent.TranslateString(xAttr.Value));
                                }
                            }
                            if (bIncludeConstraint)
                            {
                                foreach (XmlAttribute xAttr in xConstraint.Attributes)
                                {
                                    if (String.Compare(xAttr.Name, "Port", true) == 0)
                                    {
                                        // Find port pin
                                        string searchPort = xAttr.Value.Replace("(?)", string.Empty).Replace("\"", string.Empty);
                                        bool bFoundPort = false;
                                        foreach (CerebrumPropertyEntry CPEntry in CompCore.Properties.GetEntries(CerebrumPropertyTypes.PORT))
                                        {
                                            if (String.Compare(CPEntry.PropertyName, searchPort, true) == 0)
                                            {
                                                ConstraintLine = ConstraintLine.Replace(searchPort, CPEntry.PropertyName);
                                                bFoundPort = true;
                                                break;
                                            }
                                        }
                                        if (!bFoundPort)
                                        {
                                            bIncludeConstraint = false;
                                            break;
                                        }
                                    }
                                }
                            }
                            if (bIncludeConstraint)
                            {
                                foreach (XmlNode xSubNode in xConstraint.ChildNodes)
                                {
                                    string Keyword = string.Empty;
                                    string Contents = string.Empty;
                                    foreach (XmlAttribute xAttr in xSubNode.Attributes)
                                    {
                                        if (String.Compare(xAttr.Name, "Contents", true) == 0)
                                        {
                                            ConstraintLine = String.Format("{0} {1} = {2}", ConstraintLine, xSubNode.Name, xAttr.Value);
                                            break;
                                        }
                                        else if (String.Compare(xAttr.Name, "Valid", true) == 0)
                                        {
                                            // Direct contents copy
                                            if (!Conditions.EvaluateAsBoolean(CompCore.TranslateString(xAttr.Value)))
                                                break;
                                        }
                                    }
                                }
                                ConstraintLine = ConstraintLine.Replace(CompCore.NativeInstance, CompCore.CoreInstance);
                                string DoubleCore = String.Format("{0}_{0}", CompCore.OwnerComponent.CoreInstance);
                                while (ConstraintLine.Contains(DoubleCore))
                                    ConstraintLine = ConstraintLine.Replace(DoubleCore, CompCore.OwnerComponent.CoreInstance);  // Hack! To get around replacing instance name in pin names :(

                                UCFConstraints.Add(String.Format("{0}", ConstraintLine.Trim()));
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                ErrorReporting.DebugException(ex, true);
            }
        }
        #endregion

        #region Project Generation and MHS Processing

        /// <summary>
        /// Creates an empty "skeleton" XPS project using the xps command-line.
        /// </summary>
        /// <returns></returns>
        public bool CreateXPSProjects()
        {
            // create project either locally or remotly using
            // FileServices.isLocalSynthServer option.
            ProjectOpts.Builder = this;
            ConfigMHS.Builder = this;

            if (FileService.isLocalSynthServer)
            {
                // local Synthesis server

                // check if project path set
                if (ProjectOpts.XpsProjectDirectory == "")
                {
                    RaiseMessageEvent("XpsBuilder: No xps project directory was provided. set XpsProjectDirectory to a path");
                    return false;
                }
                if (ProjectOpts.XpsProjectName == "")
                {
                    RaiseMessageEvent("XpsBuilder: Project name has no value, set XpsProjectName option to a value");
                    return false;
                }

                ProcessStartInfo p_info = new ProcessStartInfo("xbash");
                p_info.RedirectStandardError = true;
                p_info.RedirectStandardInput = true;
                p_info.RedirectStandardOutput = true;
                p_info.CreateNoWindow = true;
                p_info.UseShellExecute = false;

                Process p = new Process();
                p.StartInfo = p_info;
                p.Start();

                //p.StandardInput.WriteLine("xps -nw");
                //while (! p.StandardOutput.ReadLine().Contains("XPS%"));
                //if (!tempResp.Contains("XPS%"))
                //{
                //    this.RaiseMessageEvent("XpsBuilder: Could not start XPS on synthesis server. Check installation");
                //    return false;
                //}
                foreach (string fpga in ProjectOpts.PlatFormFPGAs)
                {
                    System.IO.Directory.CreateDirectory(ProjectOpts.XpsProjectDirectory + "\\" + fpga);
                    while (!System.IO.Directory.Exists(ProjectOpts.XpsProjectDirectory + "\\" + fpga))
                        System.Threading.Thread.Sleep(1000);
                    p.StandardInput.WriteLine("xps -nw");
                    while (!p.StandardOutput.ReadLine().Contains("All rights reserved."))
                        System.Threading.Thread.Sleep(1000);
                    p.StandardInput.WriteLine("cd " + ProjectOpts.XpsProjectDirectory.Replace("\\", "/") + "/" + fpga);
                    // temp = p.StandardOutput.ReadLine();
                    //while (!temp.Contains("XPS%"))
                    //    temp = p.StandardOutput.ReadLine();
                    p.StandardInput.WriteLine("xload new {0}.xmp", ProjectOpts.XpsProjectName);
                    string temp = p.StandardOutput.ReadLine();
                    while (!temp.Contains("0"))
                        temp = p.StandardOutput.ReadLine();
                    p.StandardInput.WriteLine("exit");

                }
                ProjectOpts.XpsProjectCreated = true;
                p.Close();
            }
            else
            {
                //// Remote synthesis server
                //if (!FileService.isServerConnected)
                //{
                //    this.RaiseMessageEvent("XpsBuilder: Please use FileServices to log into remote synthesis server first");
                //    return false;
                //}

                foreach (string fpga in ProjectOpts.PlatFormFPGAs)
                {
                    //FileService.xpsShell.WriteLine("cd " + FileService.remoteDir);
                    //FileService.xpsShell.WriteLine("mkdir " + FileService.remoteDir+"/"+fpga);
                    //FileService.xpsShell.WriteLine("cd "+FileService.remoteDir+"/"+fpga);
                    //FileService.xpsShell.WriteLine("xps -nw");
                    //FileService.xpsShell.Expect("XPS%");
                    //FileService.xpsShell.WriteLine("xload new " + FileService.remoteDir + "/" + fpga+"/"+ProjectOpts.XpsProjectName + ".xmp");
                    //FileService.xpsShell.Expect("XPS%");
                    //FileService.xpsShell.WriteLine("exit");

                    StreamWriter newMHS = new StreamWriter(String.Format("{0}\\{1}.mhs", ProjectOpts.XpsProjectDirectory, ProjectOpts.XpsProjectName));
                    newMHS.Write(String.Format("\n"));
                    newMHS.Write(String.Format("PARAMETER VERSION = {0}\n", MHS_VERSION));
                    newMHS.Write(String.Format("\n"));
                    newMHS.Close();
                }
                //FileService.xpsShell.
                ProjectOpts.XpsProjectCreated = true;
            }

            return true;
        }
       
        /// <summary>
        /// Imports custom snippets of MHS-as-XML, as defined by each core, into the project.
        /// </summary>
        /// <param name="PathMan">A Project Path Manager object, with the project paths already loaded.</param>
        /// <param name="MHSPortMaps">(ref)A list of MHS external ports to be populated, as specified by the cores.</param>
        /// <returns>True if the import(s) were completed successfully.  False otherwise.</returns>
        public bool ImportCustomXMLs(PathManager PathMan, ref List<string> MHSPortMaps)
        {
            MHSPortMaps = new List<string>();
            try
            {
                foreach (CerebrumCore CC in ProjectOpts.ComponentList)
                {
                    if (CC.MappedFPGA != ProjectOpts.PlatFormFPGAs[0])
                        continue;

                    CC.ImportXMLAsMHS(ref MHSPortMaps);
                }
                return true;
            }
            catch (Exception ex)
            {
                ErrorReporting.DebugException(ex);
            }
            return false;
        }
        /// <summary>
        /// Populates a skeleton MHS file with all 'default' Pcores, only setting type, instance, and version
        /// </summary>
        /// <param name="PathMan"></param>
        public void CreateSkeletonMHS(PathManager PathMan)
        {
            string mhsFile = String.Format("{0}\\{1}.mhs", this.ProjectOpts.XpsProjectDirectory, this.ProjectOpts.XpsProjectName);
            StreamWriter mhsWriter = new StreamWriter(mhsFile);
            mhsWriter.Write(String.Format("PARAMETER VERSION = {0}\r\n", MHS_VERSION));
            mhsWriter.Write(String.Format("\r\n\r\n\r\n"));
            foreach (ComponentCore CompCore in ProjectOpts.PCoresList)
            {
                if (CompCore.MappedFPGA != ProjectOpts.PlatFormFPGAs[0])
                    continue;

                mhsWriter.Write(String.Format("BEGIN {0}\r\n", CompCore.CoreType));
                mhsWriter.Write(String.Format(" PARAMETER INSTANCE = {0}\r\n", CompCore.CoreInstance));
                mhsWriter.Write(String.Format(" PARAMETER HW_VER = {0}\r\n", CompCore.CoreVersion));
                mhsWriter.Write(String.Format("END\r\n\r\n"));
            }
            mhsWriter.Close();
        }

        /// <summary>
        /// Copies the required files for the specified Core to the local XPS project directory.  Use of the PlatformArchitecture parameter allows for 
        /// supporting cores that are customized to a specific architecture, rather than generalized to be globally compatible.
        /// </summary>
        /// <param name="Core">The structure defining the required information for the Core to be copied.</param>
        /// <param name="PlatformArchitecture">The platform architecture on which the core will be synthesized.  If not specified, a generally compatible core is assumed.</param>
        /// <returns>True if location and copying of files was successful, false otherwise.</returns>
        public bool CopyCoreFilesToXpsProject(ComponentCore Core, string PlatformArchitecture)
        {
            if (Core.CoreSource == string.Empty)
                return true;

            string ArchDir = (((PlatformArchitecture == string.Empty) || (PlatformArchitecture == null)) ? string.Empty : "\\" + PlatformArchitecture);
            string CoreFolder = Core.CoreType + "_v" + Core.CoreVersion.Replace(".", "_");
            string CoreArchFolder = CoreFolder + ArchDir;
            string CoreDir = Core.LocateCoreDirectory(PathMan);
            //string CoreArchDir = LocateCoreDirectory(PathMan, CoreArchFolder, false);

            string CoreSource = string.Empty;
            if (Directory.Exists(CoreDir + "\\data"))
            {
                CoreSource = CoreDir;
            }
            else
            {
                this.RaiseMessageEvent("WARNING: Cannot locate '{0}', assuming core is located in a 'GlobalSynthPCores' path on synthesis server.", CoreFolder);
                return true;
            }
            if (ProjectOpts.XpsProjectDirectory == "")
            {
                this.RaiseMessageEvent("XpsBuilder: No xps project directory was provided. set XpsProjectDirectory to a path");
                return false;
            }

            // copying...
            bool Successful = false;
            if (!System.IO.Directory.Exists(ProjectOpts.XpsProjectDirectory + "\\pcores"))
            {
                System.IO.Directory.CreateDirectory(ProjectOpts.XpsProjectDirectory + "\\pcores");
            }
            if (!System.IO.Directory.Exists(ProjectOpts.XpsProjectDirectory + "\\pcores\\" + CoreFolder))
            {
                System.IO.Directory.CreateDirectory(ProjectOpts.XpsProjectDirectory + "\\pcores\\" + CoreFolder);
            }
            Successful = FileService.Local_Directory_Copy(CoreSource, ProjectOpts.XpsProjectDirectory + "\\pcores\\" + CoreFolder);
            if (!Successful)
            {
                this.RaiseMessageEvent("XpsBuilder: Unable to copy pcores folders.");
                return false;
            }

            // No drivers for the time-being.
            //if (System.IO.Directory.Exists(CoreSource + "\\drivers"))
            //{
            //    // check if drivers folder exist
            //    if (!System.IO.Directory.Exists(ProjectOpts.XpsProjectDirectory + "\\drivers"))
            //    {
            //        System.IO.Directory.CreateDirectory(ProjectOpts.XpsProjectDirectory + "\\drivers");
            //    }
            //    if (!System.IO.Directory.Exists(ProjectOpts.XpsProjectDirectory + "\\drivers\\" + CoreFolder))
            //    {
            //        System.IO.Directory.CreateDirectory(ProjectOpts.XpsProjectDirectory + "\\drivers" + CoreFolder);
            //    }
            //    Successful = FileService.Local_Directory_Copy(CoreSource, ProjectOpts.XpsProjectDirectory + "\\drivers\\" + CoreFolder);
            //    if (!Successful)
            //    {
            //        this.RaiseMessageEvent("XpsBuilder: Unable to copy drivers folders.");
            //        return false;
            //    }
            //}
            //else
            //{
            //    //this.RaiseMessageEvent("XpsBuilder: No MDD file found for {0}", Core.CoreName);
            //}

            return true;
        }
        /// <summary>
        /// Adds the specification block for the specified core to the project MHS file.  
        /// </summary>
        /// <param name="Core">The structure defining the required information for the Core to be added.</param>
        /// <param name="PlatformArchitecture">The platform architecture on which the core will be synthesized.  If not specified, a generally compatible core is assumed.</param>
        /// <returns>True if addition of the core was successful, false otherwise</returns>
        public bool AddCoreSpecsToMHS(ComponentCore Core, string PlatformArchitecture)
        {
            // check if MPD file exist.
            string CoreFolder = Core.CoreType + "_v" + Core.CoreVersion.Replace(".", "_");
            string MPDFileName = Core.LocateCoreMPD(PathMan);
            FileInfo FI_File = new FileInfo(MPDFileName);

            if (!FI_File.Exists)
            {
                //this.RaiseMessageEvent("XpsBuilder: Unable to locate MPD file for core {0}, assuming Xilinx core.", Core.CoreID);
                System.IO.StreamWriter writer = new System.IO.StreamWriter(ProjectOpts.XpsProjectDirectory + "\\" + ProjectOpts.XpsProjectName + ".mhs", true);
                writer.WriteLine(String.Format("BEGIN {0}\n PARAMETER INSTANCE = {1}\n PARAMETER HW_VER = {2}\nEND\n", Core.CoreType, Core.CoreInstance, Core.CoreVersion));
                writer.Close();
                return true;
            }
            if (ProjectOpts.XpsProjectName == "")
            {
                this.RaiseMessageEvent("XpsBuilder: Project Name is not Specified");
                return false;
            }
            if (!System.IO.File.Exists(ProjectOpts.XpsProjectDirectory + "\\" + ProjectOpts.XpsProjectName + ".mhs"))
            {
                this.RaiseMessageEvent("XpsBuilder: Unable to find {0}.mhs file.", ProjectOpts.XpsProjectName);
                return false;
            }

            // OPEN MPD file and read the specification block
            string SpecBlock = "";
            string templine = "";
            System.IO.StreamReader sr = new System.IO.StreamReader(MPDFileName);
            while (!sr.EndOfStream)
            {
                templine = sr.ReadLine();
                if (templine.Contains("PARAMETER ") || templine.Contains("BUS_INTERFACE ") ||
                    templine.Contains("BEGIN "))
                {
                    if (templine.Contains(","))
                        templine = (templine.Contains("BEGIN ") ? "" : "  ") + templine.Substring(0, templine.IndexOf(','));
                    SpecBlock += templine + "\r\n";
                }
            }

            sr.Close();

            SpecBlock += "  PARAMETER INSTANCE = " + Core.CoreInstance + "\r\n";
            SpecBlock += "  PARAMETER HW_VER = " + Core.CoreVersion + "\r\n";
            SpecBlock += "END\r\n";

            // insert SpecBlock into MHS file
            System.IO.StreamWriter sw = new System.IO.StreamWriter(ProjectOpts.XpsProjectDirectory + "\\" + ProjectOpts.XpsProjectName + ".mhs", true);

            sw.WriteLine(SpecBlock);

            sw.Close();
            return true;
        }
        /// <summary>
        /// Adds the driver block for the specified core to the project MSS file.  
        /// </summary>
        /// <param name="Core">The structure defining the required information for the Core to be added.</param>
        /// <param name="PlatformArchitecture">The platform architecture on which the core will be synthesized.  If not specified, a generally compatible core is assumed.</param>
        /// <returns>True if addition of the core was successful, false otherwise</returns>
        public bool AddCoreDriverToMSS(ComponentCore Core, string PlatformArchitecture)
        {
            string CoreFolder = Core.CoreType + "_v" + Core.CoreVersion.Replace(".", "_");
            string MDDFileName = Core.LocateCoreMDD(PathMan);
            FileInfo FI_File = new FileInfo(MDDFileName);

            if (!FI_File.Exists)
            {
                //this.RaiseMessageEvent("XpsBuilder: No MDD file found for {0}", Core.CoreName);
                return false;
            }
            if (ProjectOpts.XpsProjectName == "")
            {
                //this.RaiseMessageEvent("XpsBuilder: Project Name is not Specified");
                return false;
            }
            if (!System.IO.File.Exists(ProjectOpts.XpsProjectDirectory + "\\" + ProjectOpts.XpsProjectName + ".mss"))
            {
                //this.RaiseMessageEvent("XpsBuilder: Unable to find {0}.mss file.", ProjectOpts.XpsProjectName);
                return false;
            }

            // OPEN MDD file and read the specification block
            string SpecBlock = "";
            string templine = "";
            System.IO.StreamReader sr = new System.IO.StreamReader(MDDFileName);
            while (!sr.EndOfStream)
            {
                templine = sr.ReadLine();
                if (templine.Contains("BEGIN "))
                {
                    if (templine.Contains(","))
                        templine = templine.Substring(0, templine.IndexOf(','));
                    SpecBlock += templine + "\r\n";
                }
            }
            SpecBlock = SpecBlock.Replace("BEGIN", "");
            sr.Close();
            this.RaiseMessageEvent(SpecBlock);

            //insert SpecBlock into MSS file

            string CoreDriverBlock = "BEGIN DRIVER\r\n";
            CoreDriverBlock += "  PARAMETER DRIVER_NAME = " + Core.CoreType + "\r\n";
            CoreDriverBlock += "  PARAMETER DRIVER_VER = " + Core.CoreVersion + "\r\n";
            CoreDriverBlock += "  PARAMETER HW_INSTANCE = " + Core.CoreInstance + "\r\n";
            CoreDriverBlock += "END\r\n";

            System.IO.StreamWriter sw = new System.IO.StreamWriter(ProjectOpts.XpsProjectDirectory + "\\" + ProjectOpts.XpsProjectName + ".mss", true);
            sw.WriteLine(CoreDriverBlock);
            sw.Close();
            return true;
        }

        /// <summary>
        /// Processes the set of mapped cores, and for each core mapped to the FPGA specified by the project options, its files and specifications are added to the project.
        /// </summary>
        /// <param name="CustomCoreConfigs">The path to the location of custom core configuration files to be used for the project.</param>
        /// <param name="PlatformArchitecture">The platform architecture of the current FPGA.</param>
        /// <param name="AllowEmptySynth">Boolean flag to determine whether the platform may be synthesized even if it is "empty" (i.e. no custom cores were assigned).</param>
        /// <returns>True if all cores on the current FPGA were successfully integrated into the project.</returns>
        public bool integrateCoreList(string CustomCoreConfigs, string PlatformArchitecture, bool AllowEmptySynth)
        {
            string baseRemoteDir = FileService.remoteDir;
            string localFPGADir = ProjectOpts.XpsProjectDirectory;

            foreach (string fpga in ProjectOpts.PlatFormFPGAs)
            {

                Directory.CreateDirectory(localFPGADir);
                ProjectOpts.XpsProjectDirectory = localFPGADir;
                FileService.Set_Remote_Dir(baseRemoteDir + "/" + fpga);
                FileService.Set_Local_Dir(localFPGADir);

                // Retrieve platform MHS and MSS
                //FileService.Copy_File_From(ProjectOpts.XpsProjectName + ".mhs");
                //FileService.Copy_File_From(ProjectOpts.XpsProjectName + ".mss");
                //ParseXPSBaseSystemXml();

                int coreCount = 0;
                foreach (ComponentCore CompCore in ProjectOpts.PCoresList)
                {
                    if (CompCore.MappedFPGA == fpga)
                    {
                        coreCount++;
                        CompCore.CoreSource = CompCore.LocateCoreDirectory(PathMan);
                        if (CopyCoreFilesToXpsProject(CompCore, PlatformArchitecture))
                        {
                            //AddCoreSpecsToMHS(core, PlatformArchitecture);
                            //AddCoreDriverToMSS(core, PlatformArchitecture);
                            ConfigMHS.MHSFilePath = ProjectOpts.XpsProjectDirectory + "\\" + ProjectOpts.XpsProjectName + ".mhs";

                            // Check for general configurations
                            ConfigMHS.xmlFilePath = CustomCoreConfigs + "\\" + CompCore.CoreInstance + ".xml";
                            if (File.Exists(ConfigMHS.xmlFilePath))
                            {
                                this.RaiseMessageEvent("Processing configurations for core: {0}", CompCore.CoreInstance);
                                ConfigMHS.UpdateMHSFile();
                            }

                            // Then architecture specific configurations
                            ConfigMHS.xmlFilePath = CustomCoreConfigs + "\\" + PlatformArchitecture + "\\" + CompCore.CoreInstance + ".xml";
                            if (File.Exists(ConfigMHS.xmlFilePath))
                            {
                                this.RaiseMessageEvent("Processing arch-specific configurations for core: {0}", CompCore.CoreInstance);
                                ConfigMHS.UpdateMHSFile();
                            }
                        }
                    }
                }
                FileService.Set_Remote_Dir(baseRemoteDir + "/" + fpga);
                FileService.Set_Local_Dir(localFPGADir);
                //FileService.Copy_File_To(ProjectOpts.XpsProjectName + ".mhs");
                //FileService.Copy_File_To(ProjectOpts.XpsProjectName + ".mss");
                FileService.Set_Remote_Dir(baseRemoteDir);

                if (!AllowEmptySynth)
                {
                    if (coreCount == 0)
                    {
                        this.RaiseMessageEvent("No cores located on {0} -- Pre-empting synthesis by removing MHS file.", ProjectOpts.XpsProjectName);
                        // This FPGA has no cores attached to it, there's no need to synthesize it
                        // Remove the remote MHS File
                        FileService.execShell.RunCommand(String.Format("rm {0}/system.mhs", baseRemoteDir + "/" + fpga));
                        // Delete the local MHS file
                        File.Delete(ProjectOpts.XpsProjectDirectory + "\\" + ProjectOpts.XpsProjectName + ".mhs");
                    }
                }
            }
            return true;
        }
       
        /// <summary>
        /// Parses the specified MHS file populating parameters and properties of the cores, as well as external ports
        /// </summary>
        /// <param name="MHSFile">The path to the MHS file to be read.</param>
        /// <param name="SystemBusList">(out) List of available/required system busses defined.</param>
        /// <param name="CompCores">(out) List of ComponentCore objects parsed from the MHS file.</param>
        /// <param name="Ports">(out) List of external ports defined</param>
        /// <returns>True if successful, False otherwise.</returns>
        public bool ParseMHSCores(string MHSFile, out List<string> SystemBusList, out List<ComponentCore> CompCores, out List<string> Ports)
        {
            SystemBusList = new List<string>();
            CompCores = new List<ComponentCore>();
            Ports = new List<string>();
            if (File.Exists(MHSFile))
            {
                StreamReader reader = new StreamReader(MHSFile);
                string inLine = string.Empty;
                string CurrentCoreType = string.Empty;
                string CurrentCoreInstance = string.Empty;
                string CurrentCoreVer = string.Empty;
                List<string[]> CurrentCoreParameters = new List<string[]>();

                while (!reader.EndOfStream)
                {
                    inLine = reader.ReadLine();
                    inLine = inLine.Trim();

                    if (inLine.StartsWith("BEGIN"))
                    {
                        CurrentCoreType = inLine.Substring(6).Trim();
                        CurrentCoreInstance = string.Empty;
                        CurrentCoreParameters = new List<string[]>();
                    }
                    else if (inLine.StartsWith("END"))
                    {
                        if ((CurrentCoreInstance != string.Empty) && (CurrentCoreType != string.Empty) && (CurrentCoreParameters.Count > 0))
                        {
                            ComponentCore CompCore = ProjectOpts.GetPCore(CurrentCoreInstance);
                            if (CompCore == null)
                                CompCore = new ComponentCore(CurrentCoreInstance, CurrentCoreType);
                            CompCore.CoreVersion = CurrentCoreVer;

                            // TODO: Find addresses in parameters
                            // TODO: Pair addresses in parameters  - For not assume address pairs are C_xxxxBASEADDR and C_xxxxHIGHADDR
                            // Check/Allocate addresses in ranges
                            foreach (string[] parameterLine in CurrentCoreParameters)
                            {
                                if (parameterLine.Length < 4)
                                {
                                    this.RaiseMessageEvent("An error occured reading MHS file for address verification.");
                                    break;
                                }
                                // parameterLine[0] = <TYPE>
                                // parameterLine[1] = <NAME>
                                // parameterLine[2] = "="
                                // parameterLine[3] = <VALUE>
                                if (parameterLine[0].Trim() == "PARAMETER")
                                {
                                    CerebrumPropertyEntry CPE = new CerebrumPropertyEntry();
                                    CPE.PropertyName = parameterLine[1].Trim();
                                    CPE.PropertyValue = parameterLine[3].Trim();
                                    CPE.PropertyType = CerebrumPropertyTypes.PARAMETER;
                                    CompCore.DefaultProperties.SetValue(CPE, true);
                                }
                                else if (parameterLine[0].Trim() == "BUS_INTERFACE")
                                {
                                    string BusName = String.Concat(parameterLine[1], parameterLine[2], parameterLine[3]);
                                    CerebrumPropertyEntry CPE = new CerebrumPropertyEntry();
                                    CPE.PropertyName = parameterLine[1].Trim();
                                    CPE.PropertyValue = parameterLine[3].Trim();
                                    CPE.PropertyType = CerebrumPropertyTypes.BUS_INTERFACE;
                                    CompCore.DefaultProperties.SetValue(CPE, true);

                                    if (!SystemBusList.Contains(CPE.PropertyName))
                                    {
                                        SystemBusList.Add(CPE.PropertyName);
                                    }
                                }
                                else if (parameterLine[0].Trim() == "PORT")
                                {
                                    CerebrumPropertyEntry CPE = new CerebrumPropertyEntry();
                                    CPE.PropertyName = parameterLine[1].Trim();
                                    CPE.PropertyValue = parameterLine[3].Trim();
                                    CPE.PropertyType = CerebrumPropertyTypes.PORT;
                                    CompCore.DefaultProperties.SetValue(CPE, true);
                                }
                            }
                        }
                    }
                    else if (CurrentCoreType != string.Empty)
                    {
                        if (inLine.Contains("PARAMETER INSTANCE = "))
                        {
                            int eqIdx = inLine.IndexOf("=");
                            CurrentCoreInstance = inLine.Substring(eqIdx + 1, inLine.Length - (eqIdx + 1)).Trim();
                        }
                        else if (inLine.Contains("PARAMETER HW_VER = "))
                        {
                            int eqIdx = inLine.IndexOf("=");
                            CurrentCoreVer = inLine.Substring(eqIdx + 1, inLine.Length - (eqIdx + 1)).Trim();
                        }
                        CurrentCoreParameters.Add(inLine.Split());
                    }
                    else if (inLine.StartsWith("PORT"))
                    {
                        Ports.Add(inLine);
                    }

                }
                reader.Close();
                return true;
            }
            else
            {
                return false;
            }
        }

        /// <summary>
        /// Parses the core MPD file for address information information based on current parameters and defaults.
        /// </summary>
        /// <param name="MPDPath">The path to the local MPD file to be parsed</param>
        /// <param name="CoreInfos">A List of CoreAddressRangeInfo objects, containing information about bus address ranges used by the core.  This information is ignored in the Vortex domain.</param>
        /// <param name="CompCore">A ComponentCore object whose addresses are to be read.</param>
        public void ReadBusAddressParameters(string MPDPath, out List<CoreAddressRangeInfo> CoreInfos, ComponentCore CompCore)
        {
            CoreInfos = new List<CoreAddressRangeInfo>();
            StreamReader reader = new StreamReader(MPDPath);
            string inLine;
            Dictionary<string, CoreAddressRangeInfo> Infos = new Dictionary<string, CoreAddressRangeInfo>();
            try
            {
                while (!reader.EndOfStream)
                {
                    inLine = reader.ReadLine();
                    inLine = inLine.Trim();
                    if (inLine.StartsWith("PARAMETER"))
                    {
                        // Extract the parameter name/value pair as default
                        {
                            string[] pArgs = inLine.Split(',');
                            for (int i = 0; i < pArgs.Length; i++)
                            {
                                pArgs[i] = pArgs[i].Trim();
                                if (pArgs[i].StartsWith("PARAMETER "))
                                {
                                    string tempString = pArgs[i].Substring(pArgs[i].IndexOf(" ")).Trim();
                                    string pName = tempString.Substring(0, tempString.IndexOf("=")).Trim();
                                    string pValue = tempString.Substring(tempString.IndexOf("=") + 1).Trim();
                                    CompCore.DefaultProperties.SetValue(CerebrumPropertyTypes.PARAMETER, pName, pValue, true);
                                    break;
                                }
                            }
                        }
                        if (inLine.Contains("ADDRESS = "))
                        {
                            string[] pArgs = inLine.Split(',');
                            string pName = string.Empty;
                            string pBase = string.Empty;
                            string pHigh = string.Empty;
                            string pPair = string.Empty;
                            string pLoc = string.Empty;
                            string pBus = string.Empty;
                            string pMin = string.Empty;
                            string pValidCond = string.Empty;
                            bool pReq = false;
                            for (int i = 0; i < pArgs.Length; i++)
                            {
                                pArgs[i] = pArgs[i].Trim();
                                if (pArgs[i].StartsWith("PARAMETER "))
                                {
                                    string tempString = pArgs[i].Substring(pArgs[i].IndexOf(" ")).Trim();
                                    pName = tempString.Substring(0, tempString.IndexOf(" ")).Trim();
                                }
                                else if (pArgs[i].StartsWith("BUS = "))
                                {
                                    pBus = pArgs[i].Substring("BUS =".Length).Trim();
                                }
                                else if (pArgs[i].StartsWith("ADDRESS = "))
                                {
                                    pLoc = pArgs[i].Substring("ADDRESS =".Length).Trim().ToUpper();
                                }
                                else if (pArgs[i].StartsWith("PAIR = "))
                                {
                                    pPair = pArgs[i].Substring("PAIR =".Length).Trim();
                                }
                                else if (pArgs[i].StartsWith("MIN_SIZE = "))
                                {
                                    pMin = pArgs[i].Substring("MIN_SIZE =".Length).Trim();
                                }
                                else if (pArgs[i].ToUpper().Contains("ASSIGNMENT = REQUIRE"))
                                {
                                    pReq = true;
                                }
                                else if (pArgs[i].ToUpper().Contains("ISVALID = "))
                                {
                                    pValidCond = pArgs[i].Substring("ISVALID =".Length).Trim();
                                }
                            }
                            if (pLoc == "BASE")
                            {
                                // This address is the base, high is the pair
                                pBase = pName;
                                pHigh = pPair;
                            }
                            else if (pLoc == "HIGH")
                            {
                                // This address is the high, base is the pair
                                pBase = pPair;
                                pHigh = pName;
                            }
                            string[] BusList = pBus.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries);

                            if (Infos.ContainsKey(pBase))
                            {
                                CoreAddressRangeInfo CI = Infos[pBase];
                                // Sanity check -- verify the pair
                                if ((CI.BaseName == pBase) && (CI.HighName == pHigh))
                                {
                                    CI.BaseParameter = CompCore.DefaultProperties.GetEntry(CerebrumPropertyTypes.PARAMETER, CI.BaseName);
                                    CI.HighParameter = CompCore.DefaultProperties.GetEntry(CerebrumPropertyTypes.PARAMETER, CI.HighName);
                                    // Update the min size if needed
                                    if ((CI.MinSize == string.Empty) && (pMin != string.Empty))
                                        CI.MinSize = pMin;
                                    // Update the parameter valid condition
                                    if ((CI.IsValidCond == string.Empty) && (pValidCond != string.Empty))
                                        CI.IsValidCond = pMin;
                                    // Update the bus name if needed
                                    if ((CI.LegalBusList.Count == 0))
                                        CI.LegalBusList.AddRange(BusList);
                                    // Update the required flag if needed
                                    if (!CI.Required && pReq)
                                        CI.Required = pReq;
                                }
                            }
                            else
                            {
                                // Add this bus interface using the base as the name
                                CoreAddressRangeInfo CI = new CoreAddressRangeInfo();
                                CI.BaseName = pBase;
                                CI.HighName = pHigh;
                                CI.BaseParameter = CompCore.DefaultProperties.GetEntry(CerebrumPropertyTypes.PARAMETER, CI.BaseName);
                                CI.HighParameter = CompCore.DefaultProperties.GetEntry(CerebrumPropertyTypes.PARAMETER, CI.HighName);
                                // Update the min size if needed
                                if ((CI.MinSize == string.Empty) && (pMin != string.Empty))
                                    CI.MinSize = pMin;
                                // Update the parameter valid condition
                                if ((CI.IsValidCond == string.Empty) && (pValidCond != string.Empty))
                                    CI.IsValidCond = pValidCond;
                                // Update the bus name if needed
                                if ((CI.LegalBusList.Count == 0))
                                    CI.LegalBusList.AddRange(BusList);
                                // Update the required flag if needed
                                if (!CI.Required && pReq)
                                    CI.Required = pReq;

                                Infos.Add(pBase, CI);
                            }
                        }
                    }
                }
                foreach (string key in Infos.Keys)
                {
                    CoreAddressRangeInfo CI = Infos[key];
                    CoreInfos.Add(CI);
                }
            }
            catch (Exception ex)
            {
                this.RaiseMessageEvent(ErrorReporting.ExceptionDetails(ex));
                ErrorReporting.DebugException(ex);
            }
            finally
            {
                if (reader != null)
                {
                    reader.Close();
                    reader = null;
                }
            }
        }
        
        /// <summary>
        /// Rewrites the specified MHS file given the Cores, PortMaps, and External Port Lists defined.
        /// </summary>
        /// <param name="MHSFile">The path to the MHS file to be rewritten</param>
        /// <param name="CompCores">List of ComponentCore object representations.</param>
        /// <param name="Ports">List of external ports to be defined in the MHS file.</param>
        public void RewriteMHS(string MHSFile, List<ComponentCore> CompCores, List<string> Ports)
        {
            #region CHIPSCOPE SUPPORT (Extraction)
            ChipscopeController CSIcon = null;
            if (this.AutoInferChipscopes)
            {
                CSIcon = new ChipscopeController("chipscope_icon_0");
                string ILAClock = GenerateSystemClockSignal(this.PathMan, CompCores);
                foreach (ComponentCore CompCore in CompCores)
                {
                    foreach (string CSPort in CompCore.ChipscopePorts)
                    {
                        string ScopePort = CSIcon.AddILA(CompCore.CoreInstance, CSPort, ILAClock);
                        CompCore.Properties.SetValue(CerebrumPropertyTypes.PORT, CSPort, ScopePort, true);
                    }
                }
            }
            #endregion

            StreamWriter writer = new StreamWriter(MHSFile);
            writer.Write("PARAMETER VERSION = {0}\n\n", XpsBuilder.MHS_VERSION);
            foreach (string Port in Ports)
            {
                writer.Write(String.Format("{0}\n", Port));
            }
            writer.Write("\n\n");
            foreach (ComponentCore CompCore in CompCores)
            {
                CompCore.WriteMHSBlock(writer);
            }

            #region CHIPSCOPE SUPPORT (Insertion)
            if (this.AutoInferChipscopes)
            {
                if (CSIcon != null)
                {
                    if (CSIcon.NumControlPorts > 0)
                    {
                        writer.Write(CSIcon.GetChipscopeBlocks().ToString());
                    }
                }
            }
            #endregion

            writer.Close();
            writer = null;
        }

        /// <summary>
        /// Gets a signal name that is associated with a clock signal matching the frequency of the project system clock.
        /// </summary>
        /// <param name="PathMan">The Project PathManager object containing the parameter for the system clock frequency.</param>
        /// <param name="CompCores">List of ComponentCore object representations.</param>
        /// <returns>A string indicating the signal name that corresponds to a signal that matches the frequency of the project system clock.</returns>
        private string GenerateSystemClockSignal(PathManager PathMan, List<ComponentCore> CompCores)
        {
            string SystemClock = string.Empty;
            ClockSignal DesiredClock = new ClockSignal();
            long DesiredFrequency = 100000000;
            string DefaultFrequency = "100MHZ";
            string ProjectFrequency = DefaultFrequency;
            if (PathMan.HasPath("SystemFrequency"))
            {
                ProjectFrequency = PathMan["SystemFrequency"].ToUpper();
            }
            ProjectFrequency = ProjectFrequency.Replace("GHZ", "000MHZ");
            ProjectFrequency = ProjectFrequency.Replace("MHZ", "000KHZ");
            ProjectFrequency = ProjectFrequency.Replace("KHZ", "000HZ");
            ProjectFrequency = ProjectFrequency.Replace("HZ", "");
            long.TryParse(ProjectFrequency, out DesiredFrequency);

            DesiredClock.Frequency = DesiredFrequency;
            DesiredClock.Phase = 0;
            DesiredClock.Group = ClockGroup.NONE;
            DesiredClock.Buffered = true;
            DesiredClock.SignalDirection = ClockDirection.INPUT;

            List<ComponentCore> ClockGeneratorCores = new List<ComponentCore>();

            foreach (ComponentCore CompCore in CompCores)
            {
                if (CompCore.OwnerComponent == null)
                {
                    if (String.Compare(CompCore.CoreType, "clock_generator") == 0)
                    {
                        ClockGeneratorCores.Add(CompCore);
                    }
                    continue;
                }
                CerebrumCore CC = CompCore.OwnerComponent;
                {
                    foreach (ClockSignal CS in CC.OutputClocks)
                    {
                        if (CS.IsCompatibleWith(DesiredClock))
                        {
                            SystemClock = CS.GenerateCoreSignal();
                            break;
                        }
                    }
                    if (SystemClock != string.Empty)
                        break;
                }
                if (SystemClock != string.Empty)
                    break;
            }
            if (SystemClock == string.Empty)
            {
                foreach (ComponentCore ClockGeneratorCore in ClockGeneratorCores)
                {
                    if (ClockGeneratorCore != null)
                    {
                        for (int i = 0; i < 16; i++)
                        {
                            string CLK_i_FREQ = (string)ClockGeneratorCore.Properties.GetValue(CerebrumPropertyTypes.PARAMETER, String.Format("C_CLKOUT{0}_FREQ", i));
                            if (String.Compare(CLK_i_FREQ, DesiredFrequency.ToString()) == 0)
                            {
                                SystemClock = (string)ClockGeneratorCore.Properties.GetValue(CerebrumPropertyTypes.PORT, String.Format("CLKOUT{0}", i));
                                break;
                            }
                        }
                    }
                    if (SystemClock != string.Empty)
                        break;
                }
            }
            return SystemClock;
        }

        #endregion

        #region Achiving and Uploading

        /// <summary>
        /// Packages the entire set of projects as a TAR archive, sends it to the synthesis server, and un-TARs the archive remotely.
        /// </summary>
        /// <param name="LocalDir">The local directory in which the TAR archive is to be created.</param>
        /// <param name="RemoteDir">The remote directory to which the TAR archive is to be uploaded.</param>
        /// <returns>Returns true, if successful; false otherwise.</returns>
        public bool UploadCerebrumFiles(string LocalDir, string RemoteDir)
        {
            try
            {
                if (!FileService.isLocalSynthServer)
                {
                    this.RaiseMessageEvent("Transferring project files to synthesis server...");
                    FileInfo fi = new FileInfo(PathMan["ProjectTemp"] + "\\platforms.tar");
                    if (fi.Exists)
                        fi.Delete();
                    TarFolder(LocalDir, fi.FullName);

                    FileService.Set_Local_Dir(fi.Directory.FullName);
                    string RDir = string.Empty;
                    string[] Dirs = RemoteDir.Split('/');
                    for (int i = 1; i < Dirs.Length; i++)
                    {
                        RDir = String.Format("{0}/{1}", RDir, Dirs[i]);
                        FileService.execShell.RunCommand(String.Format("mkdir {0}", RDir));
                    }
                    FileService.Set_Remote_Dir(RemoteDir);
                    FileService.Copy_File_To(fi.Name);

                    FileService.execShell.RunCommand(String.Format("cd {0};tar xvf {1};rm {1}", RemoteDir, fi.Name));
                    fi.Delete();
                    this.RaiseMessageEvent("\tComplete!");
                }
            }
            catch(Exception ex)
            {
                this.RaiseMessageEvent("ERROR! {0}", ex.Message);
                return false;
            }
            return true;
        }

        private static void TarFolder(string LocalDir, string OutputFile)
        {
            FileStream fsTar = new FileStream(OutputFile, FileMode.CreateNew, FileAccess.ReadWrite, FileShare.None);
            TarArchive tar = TarArchive.CreateOutputTarArchive(fsTar);
            AddFolderToTar(tar, LocalDir, LocalDir);
            tar.Close();
            fsTar.Close();
        }
        private static void AddFolderToTar(TarArchive tar, string Folder, string RelativeTo)
        {
            string curDir = Directory.GetCurrentDirectory();
            Directory.SetCurrentDirectory(RelativeTo);
            string[] dirs = Directory.GetDirectories(Folder);
            foreach (string dir in dirs)
            {
                AddFolderToTar(tar, dir, RelativeTo);
            }
            string[] files = Directory.GetFiles(Folder);
            foreach (string file in files)
            {
                string thisFile = file.Replace(RelativeTo, string.Empty);
                if (thisFile.StartsWith("\\"))
                    thisFile = thisFile.Substring(1);
                TarEntry tarEntry = TarEntry.CreateEntryFromFile(thisFile);
                tar.WriteEntry(tarEntry, true);
            }
            Directory.SetCurrentDirectory(curDir);
        }

        #endregion

        #region IFalconLibrary Members

        /// <summary>
        /// Returns the name of this library component.  Implementation of FalconGlobal.IFalconLibrary.FalconComponentName.
        /// </summary>
        public string FalconComponentName
        {
            get { return "Falcon XPS Builder"; }
        }

        /// <summary>
        /// Returns the version of this library component.  Implementation of FalconGlobal.IFalconLibrary.FalconComponentVersion.
        /// </summary>
        public string FalconComponentVersion
        {
            get { return "Version 1.0.0"; }
        }


        /// <summary>
        /// Returns the name/version/copyright information of this library component.  Implementation of 
        /// FalconGlobal.IFalconLibrary.GetFalconComponentVersion().
        /// </summary>
        public string GetFalconComponentVersion()
        {
            return "Falcon XPS Builder 1.0.0 Copyright (c) 2010 PennState";
        }

        #endregion
    }
}
